#include "Server.h"

#include "CertificateManager.h"
#include "Channel.h"
#include "DDAP.pb.h"
#include "DdapData.h"
#include "ECCOper.h"
#include "EventLoop.h"
#include "EventLoopThreadPool.h"
#include "HandshakeTaskQueue.h"
#include "HandshakeThreadPool.h"
#include "Logging.h"
#include "MessageDispatcher.h"
#include "SymmetricEncryption.h"
#include "thread.h"
#include "utils.h"

#include <any>
#include <arpa/inet.h>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <functional>
#include <iostream>
#include <memory>
#include <mqueue.h>
#include <mutex>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>
#include <openssl/types.h>
#include <openssl/x509.h>
#include <ostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <strings.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <tuple>
#include <unistd.h>
#include <vector>

namespace droneswarm
{
    // thread_local EVP_PKEY *Server::ServerPrivKey_ = nullptr;
    Server::Server( EventLoop *loop, int threadNum, int port )
        : loop_( loop )
        , dispatcher_( new MessageDispatcher() )
        , threadNum_( threadNum )
        , eventLoopThreadPool_( new EventLoopThreadPool( loop_, threadNum ) )
        , started_( false )
        , accpetChannel_( new Channel( loop_ ) )
        , port_( port )
        , listenFd_( socket_bind_listen( port_ ) )
        , EccKeyPair_( NULL )
        , ServerPrivKey_( NULL )
        , ServerCert_( NULL )
        , serverPriBn_( NULL )
        , TaskQueue_( new HandshakeTaskQueue() )
        , shakeHandManager_( std::bind( &Server::shakeHandManagerThread, this ) )
    //, ctx_( initializeSSL() )
    {
        //封装监听listenFd_为channel
        accpetChannel_->set_fd( listenFd_ );
        handle_for_sigpipe();
        //设置描述符为非非阻塞模式
        if ( setSocketNonBlocking( listenFd_ ) < 0 )
        {
            perror( "set socket non block failed" );
            abort();
        }

        // CA证书的私钥已经在cert_对象初始化时就已经加载了。
        //验证一下公钥证书和私钥是否存在
        bool verPrivK =
            cert_.Extract_and_verify_privKey_is_valid( &ServerPrivKey_, "../KeyCert_Server/server_key.pem" );
        bool verCert = Extract_and_verify_cert_is_valid( &ServerCert_, "../KeyCert_Server/server_cert.pem" );
        if ( !verCert || !verPrivK )
        {
            //重新生成私钥和公钥证书
            std::shared_ptr< BIGNUM > serverPrivK_ = ecc_.GeneratePriKey();
            std::shared_ptr< EC_POINT > serverPubK_ = ecc_.GeneratePubKey( serverPrivK_.get() );
            int ret =
                ecc_.BN_ECKey_Conv_EC_EVPKey( serverPrivK_.get(), serverPubK_.get(), ecc_.getGroup(), &EccKeyPair_ );
            if ( !ret )
            {
                std::cout << "Failed to generate the public and private key pair. Please run the program again."
                          << std::endl;
                exit( EXIT_FAILURE );
            }
            //生成公私钥对成功，通过公私钥对来产生PEM。
            //首先保存私钥
            bool savePriv = cert_.savePrivateKey( EccKeyPair_, "../KeyCert_Server/server_key.pem" );
            if ( !savePriv )
            {
                std::cout << "Failed to save the private key. Please run the program again." << std::endl;
                exit( EXIT_FAILURE );
            }
            std::map< std::string, std::string > subjectInfo;
            subjectInfo[ "C" ] = "CN";
            subjectInfo[ "ST" ] = "Sichuan";
            subjectInfo[ "L" ] = "Chengdu";
            subjectInfo[ "O" ] = "China Electronics Technology Group";
            subjectInfo[ "CN" ] = "DroneSystem_Central_node_server";
            //产生公钥证书REQ
            X509_REQ *req = cert_.generateCSR( subjectInfo, EccKeyPair_ );
            if ( !req )
            {
                std::cout << "Failed to generateCSR. Please run the program again." << std::endl;
                exit( EXIT_FAILURE );
            }
            ServerCert_ = cert_.generateCert( req, 60 );
            if ( !ServerCert_ )
            {
                std::cerr << "Certificate generation failed. Please run the program again." << std::endl;
                X509_REQ_free( req );
                exit( EXIT_FAILURE );
            }
            //保存公钥证书
            bool saveRet = cert_.saveCertificate( ServerCert_, "../KeyCert_Server/server_cert.pem" );
            if ( !saveRet )
            {
                std::cerr << "Failed to save the public key certificate, please rerun the program(99)" << std::endl;
                X509_free( ServerCert_ );
                exit( EXIT_FAILURE );
            }
            //释放内部资源
            X509_REQ_free( req );
        }
        //到了这里证书和私钥都产生了
        bool extractPriBn = ecc_.extract_Pub_Priv_Frome_EVP_PKEY( ServerPrivKey_, &serverPriBn_, NULL, ONLYGETPRIKEY );
        if ( !extractPriBn )
        {
            std::cerr << "ERROR: extract_Pub_Priv_Frome_EVP_PKEY" << std::endl;
            X509_free( ServerCert_ );
            EVP_PKEY_free( ServerPrivKey_ );
            exit( EXIT_FAILURE );
        }
        //到这里需要提取出私钥
    }
    Server::~Server()
    {  // EVP_PKEY *EccKeyPair_;
        // X509 *ServerCert_;
        //释放上面两个资源
        EVP_PKEY_free( EccKeyPair_ );
        BN_free( serverPriBn_ );
        EVP_PKEY_free( ServerPrivKey_ );
        X509_free( ServerCert_ );
        delete dispatcher_;
    }

    //服务器开启
    void Server::start()
    {
        //开启线程池
        eventLoopThreadPool_->start();
        //设置accpetChannel_的属性
        accpetChannel_->set_Events( EPOLLIN | EPOLLET );
        accpetChannel_->setReadHandler( std::bind( &Server::handleNewConn, this ) );
        accpetChannel_->setConnHandler( std::bind( &Server::handleThisConn, this ) );
        loop_->addToPoller( accpetChannel_ );
        started_ = true;
        std::cout << "Server 已开启!!" << std::endl;
        shakeHandManager_.start();
        //同时需要开启消息队列
        bool startRet = startPOSIXMsgQueue();
        if ( !startRet )
        {
            exit( EXIT_FAILURE );
        }
    }

    bool Server::startPOSIXMsgQueue()
    {
        mq_ = mq_open( QUEUE_NAME, O_RDWR );
        if ( mq_ == ( mqd_t )-1 )
        {
            perror( "MQ Open" );
            return false;
        }
        // std::cout << mq_ << std::endl;
        dispatcher_->initDispatcher( mq_ );
        return true;
    }

    void Server::handleNewConn()
    {
        struct sockaddr_in client_addr;
        memset( &client_addr, 0, sizeof( struct sockaddr_in ) );
        socklen_t client_addr_len = sizeof( client_addr );
        int accept_fd = 0;

        while ( ( accept_fd = accept( listenFd_, ( struct sockaddr * )&client_addr, &client_addr_len ) ) > 0 )
        {

            EventLoop *loop = eventLoopThreadPool_->getNextLoop();
            LOG << "New connection from " << inet_ntoa( client_addr.sin_addr ) << ":" << ntohs( client_addr.sin_port );
            std::cout << "New connection from:" << inet_ntoa( client_addr.sin_addr ) << ":"
                      << ntohs( client_addr.sin_port ) << std::endl;
            /*
            // TCP的保活机制默认是关闭的
            int optval = 0;
            socklen_t len_optval = 4;
            getsockopt(accept_fd, SOL_SOCKET,  SO_KEEPALIVE, &optval, &len_optval);
            cout << "optval ==" << optval << endl;
            */
            // 限制服务器的最大并发连接数
            // if ( accept_fd >= MAXFDS )
            // {
            //     ssl->SSLShutDown();
            //     ssl->SSLFree();
            //     close( accept_fd );
            //     continue;
            // }
            // 设为非阻塞模式
            // if ( setSocketNonBlocking( accept_fd ) < 0 )
            // {
            //     LOG << "Set non block failed!";
            //     // perror("Set non block failed!");
            //     return;
            // }
            //创建任务
            auto taskData =
                std::make_tuple( loop, accept_fd, std::ref( ecc_ ), std::ref( cert_ ), ServerPrivKey_, serverPriBn_ );
            std::any taskArg = taskData;
            auto boundFunc = std::bind( &Server::processShakeHandTask, this, std::placeholders::_1 );
            HandshakeTask task( boundFunc, taskArg );
            // task.function(task.arg);
            TaskQueue_->addTask( task );
        }
        accpetChannel_->set_Events( EPOLLIN | EPOLLET );
    }
    void Server::shakeHandManagerThread()
    {

        HandshakeThreadPool pool( 10 );
        pool.start();
        std::vector< std::unique_ptr< Thread > > &threadPool = pool.getThreadPool();
        // std::mutex mutex;

        //遍历线程池，空闲的线程
        while ( started_ )
        {
            // std::cout << "Task number: " << TaskQueue_->taskNumber() << std::endl;
            // std::cout << "Thread pool size: " << threadPool.size() << std::endl;
            //  std::unique_lock< std::mutex > lock( mutex );
            //  cv_.wait( lock, [ this ]() { return TaskQueue_->taskNumber() > 0 || !started_; } );
            if ( !started_ )
            {
                break;
            }
            // std::cout << "执行这了没？" << std::endl;
            if ( TaskQueue_->taskNumber() > 0 )
            {
                //先去任务

                for ( auto &thread : threadPool )
                {
                    bool started = thread->started();
                    if ( !started && TaskQueue_->taskNumber() > 0 )
                    {
                        //循环的时候仍然需要判断任务队列中还有没有数据，不判断的话，他就只会一下执行4次
                        //但是此时任务队列中取不到数据了，就会报错。执行的前提就是任务队列中有任务。
                        //从任务队列中取任务
                        HandshakeTask task = TaskQueue_->takeTask();
                        std::function< void() > tempFunc = [ task ]() { task.function( task.arg ); };
                        thread->setThreadFunc( tempFunc );
                        thread->start();
                    }
                }
            }
        }
    }

    void Server::processShakeHandTask( std::any arg )
    {
        auto taskData =
            std::any_cast< std::tuple< EventLoop *, int, ECCOperator &, CertificateManager &, EVP_PKEY *, BIGNUM * > >(
                arg );

        // auto &taskData = *taskDataPtr;
        EventLoop *loop = std::get< 0 >( taskData );
        int accept_fd = std::get< 1 >( taskData );
        ECCOperator &ecc_ = std::get< 2 >( taskData );
        CertificateManager &cert = std::get< 3 >( taskData );
        EVP_PKEY *serverPri = std::get< 4 >( taskData );
        BIGNUM *serverPriBn = std::get< 5 >( taskData );
        // std::cout << "serverPriBn: " << BN_bn2dec( serverPriBn ) << std::endl;
        //  ServerPrivKey_ = serPri;
        //接收证书数据
        char receiveBuff[ 4096 ] = { 0 };
        char sendBuff[ 4096 ] = { 0 };
        char tmpBuff[ 4096 ] = { 0 };  //
        //定义读取失败的次数，超过4次就退出
        // int failedCount = 3;
        // int readcount = 10;  //数据未到达时读取数据的次数，如果超过这个次数，说明网络不好，或连接断开
        // ssize_t bytesRead = 0;
        // ssize_t totalBytesRead = 0;
        //不能每次循环都序列化一次吧，因此需要使用一个标签来设置是否已经序列化了
        SigningMessage signMessage;
        FullMessage message;
        messageInfo msInfo;

        /******************************处理AUTH_RESQUEST**************** */
        bool ret = readAndDeserialize(
            signMessage, accept_fd, receiveBuff, tmpBuff, sizeof( receiveBuff ), sizeof( tmpBuff ), 10000 );
        if ( !ret )
        {
            std::cerr << "读取数据失败" << std::endl;
            close( accept_fd );
            return;
        }

        const std::string FullmessageData = signMessage.fullmessagestring();

        const std::string signData = signMessage.signstring();

        //反序列化对象
        if ( !message.ParseFromString( FullmessageData ) )
        {
            std::cerr << "序列化SigningMessage消息失败" << std::endl;
            close( accept_fd );
            return;
        }

        //读取完成
        memset( receiveBuff, 0, sizeof( receiveBuff ) );
        memset( tmpBuff, 0, sizeof( tmpBuff ) );

        bool parseMessageResult = parseMessage( message, msInfo, accept_fd );

        if ( !parseMessageResult )
        {
            std::cerr << "数据校验不通过" << std::endl;
            return;
        }

        //分析通过，所有数据都放入到messageInfo结构体中。

        char data_c[ msInfo.realDataLength ];

        memcpy( data_c, msInfo.realData.c_str(), msInfo.realDataLength );
        X509 *ControlCert = NULL;

        ControlCert = cert.PemCharToX509( data_c, msInfo.realDataLength );

        if ( !ControlCert )
        {
            std::cerr << "X509 *cert is NULL" << std::endl;
            close( accept_fd );
            return;
        }
        //需要验证证书到没到期
        bool is_valid = check_certificate_content_validity_period( ControlCert );
        if ( !is_valid )
        {
            std::cout << "证书内容不正确或时间已到期" << std::endl;
            close( accept_fd );
            return;
        }
        EVP_PKEY *controlPubKey = NULL;
        //使用CA的公钥来验证证书的合法性
        bool cert_is_lawful = cert.verifyCert( ControlCert, &controlPubKey );
        if ( !cert_is_lawful )
        {
            std::cerr << "X509 *cert 格式不正确" << std::endl;
            if ( controlPubKey )
            {
                EVP_PKEY_free( controlPubKey );
            }
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }

        //验证签名
        bool verityRet = ecc_.verifyEDSAsignature( controlPubKey, FullmessageData, signData );
        if ( !verityRet )
        {
            std::cerr << "消息签名验证失败，消息可能被篡改且无法验证来源" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }
        // else
        // {
        //     std::cout << "数字签名验证通过，已确定发送来源" << std::endl;
        // }

        /*****************************发送AUTH_RESPONSE*************************************/

        //然后需要发送自己的公钥证书给对等方
        std::string certString = cert.readPemFile( "../KeyCert_Server/server_cert.pem" );
        size_t certStringLen = certString.size();

        setMessageInfo( msInfo, AUTH_RESPONSE );

        msInfo.realData = certString;
        msInfo.realDataLength = certStringLen;
        // std::string ss =
        //     constructMessage( certString, certStringLen, AUTH_RESPONSE, "V1", 0, 0, needAck, fragment, is_Encry, cpt,
        //     enct
        //     );
        std::string AuthResponseString = constructMessage( message, msInfo );

        //计算ss的签名
        std::string signStr = ecc_.generateESDSASignature( serverPri, AuthResponseString );

        signMessage.set_fullmessagestring( AuthResponseString );
        signMessage.set_signstring( signStr );

        //将signMessage序列化
        std::string sendString;
        if ( !signMessage.SerializePartialToString( &sendString ) )
        {
            std::cerr << "AUTH_RESPONSE 消息反序列化失败 " << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }

        size_t sendstrLen = sendString.size();
        memcpy( sendBuff, sendString.c_str(), sendstrLen );

        size_t n = write( accept_fd, sendBuff, sendstrLen );

        std::cout << "AUTH_RESPONSE 消息发送成功，大小为： " << n << std::endl;

        /*********************************处理AUTH_ACK************************************/

        bool read2 = readAndDeserialize(
            signMessage, accept_fd, receiveBuff, tmpBuff, sizeof( receiveBuff ), sizeof( tmpBuff ), 10000 );
        if ( !read2 )
        {
            std::cerr << "读取数据失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }

        //获取FullmessageString
        std::string FullMessageString = signMessage.fullmessagestring();
        std::string signStr2 = signMessage.signstring();

        //因为之前已经提取了对端的公钥，因此可以先验证签名
        bool verRet = ecc_.verifyEDSAsignature( controlPubKey, FullMessageString, signStr2 );
        if ( !verRet )
        {
            std::cerr << "验证AUTH_ACK消息的签名失败！" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }

        // std::cout << "AUTH_ACKNOWLEDGEMENT消息的数字签名验证通过" << std::endl;

        //反序列化FullMessageString
        if ( !message.ParseFromString( FullMessageString ) )
        {
            std::cerr << "从FullMessageString反序列化数据到FullMessage失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            close( accept_fd );
            return;
        }

        //分析
        bool ret3 = parseMessage( message, msInfo, accept_fd );
        if ( !ret3 )
        {
            std::cerr << "报文分析失败，可能是格式不正确" << std::endl;
            return;
        }
        
        std::string saltData = msInfo.realData;
        // size_t saltDataLen = messageInfo.realDataLength;
        std::vector< unsigned char > salt( saltData.begin(), saltData.end() );

        EC_POINT *controlPubEc = NULL;
        bool ret2 = ecc_.extract_Pub_Priv_Frome_EVP_PKEY( controlPubKey, NULL, &controlPubEc, ONLYGETPUBKEY );
        if ( !ret2 )
        {
            // std::cerr << "extract_Pub_Priv_Frome_EVP_PKEY_PUBLIC is error!" << std::endl;

            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            close( accept_fd );
            return;
        }
        unsigned char symmetricKey[ 32 ];
        bzero( symmetricKey, 32 );

        //然后计算共享密钥
        if ( !ecc_.deriveSymmetricKey( ecc_.getGroup(), controlPubEc, serverPriBn, salt.data(), symmetricKey ) )
        {
            std::cerr << "deriveSymmetricKey is error!" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            EC_POINT_free( controlPubEc );
            close( accept_fd );
            return;
        }
        // std::string symm_str = base64_encode( symmetricKey, 32 );
        // std::cout << symm_str << std::endl;
        /************************************发送ACK_FINAL_ACK消息*******************************/

        setMessageInfo( msInfo, AUTH_FINAL_ACKNOWLEDGEMENT );
        std::string sourceData = "数据已正确收到";

        msInfo.realData = sourceData;
        msInfo.realDataLength = sourceData.size();
        //构造对象
        std::string fullMessageString = constructMessage( message, msInfo );
        size_t fullMessageStringLen = fullMessageString.size();

        SymmetricEncryption symm;
        //设置IV和密钥
        symm.setIv();
        symm.setSymmeticKey( symmetricKey );

        //设置加密缓冲区的大小
        int cipherTextLen = 0;
        //设置加密数据缓冲区
        unsigned char cipherText[ 4096 ];
        //明文缓冲区
        unsigned char plainText[ fullMessageStringLen ];
        int plainTextLen = fullMessageStringLen;
        memcpy( plainText, fullMessageString.c_str(), fullMessageStringLen );
        //加密数据
        bool encryptRet = symm.aes_Encryption( plainText, plainTextLen, cipherText, &cipherTextLen );
        if ( !encryptRet )
        {
            std::cerr << "加密数据失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            EC_POINT_free( controlPubEc );
            close( accept_fd );
            return;
        }

        //将密文构造成字符串
        std::string cipherString( reinterpret_cast< const char * >( cipherText ), cipherTextLen );
        //需要获取IV，将IV放入到EncrptyMessage中
        unsigned char *iv = symm.getIv();

        std::string iv_str( reinterpret_cast< const char * >( iv ), 16 );
        EncrptyMessage encryptMessage;
        encryptMessage.set_iv( iv_str );
        encryptMessage.set_encryptedfullmessagestring( cipherString );
        // FullMessage消息的序列化之后的字符串已经加密了，因此我们需要填入到

        //然后就是将encryptMessage消息序列化成字符串之后生成hmac
        std::string encryptMessageString;
        bool enStrRet = encryptMessage.SerializePartialToString( &encryptMessageString );
        if ( !enStrRet )
        {
            std::cerr << "encryptMessage序列化失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            EC_POINT_free( controlPubEc );
            close( accept_fd );
            return;
        }

        //计算Hmac
        size_t encryptMessageStringLen = encryptMessageString.size();
        unsigned char encryptMessagString_c[ encryptMessageStringLen ];
        memcpy( encryptMessagString_c, encryptMessageString.c_str(), encryptMessageStringLen );
        unsigned char *hmac_value = NULL;
        size_t hmac_value_len = 0;
        bool geneHmacRet = generateHmac(
            encryptMessagString_c, encryptMessageStringLen, symmetricKey, 32, &hmac_value, &hmac_value_len );
        if ( !geneHmacRet )
        {
            std::cerr << "encryptMessage序列化失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            EC_POINT_free( controlPubEc );
            close( accept_fd );
            return;
        }

        std::string hmac_value_str( reinterpret_cast< const char * >( hmac_value ), hmac_value_len );

        needHMACMessage hmacMessage;
        hmacMessage.set_encrptymessagestring( encryptMessageString );
        hmacMessage.set_hmacstring( hmac_value_str );

        // needHMACMessage进行序列化生成字符串
        std::string hmacMessageString;
        bool hmacMessageSeRet = hmacMessage.SerializePartialToString( &hmacMessageString );
        if ( !hmacMessageSeRet )
        {
            std::cerr << "hmacMessage序列化失败" << std::endl;
            EVP_PKEY_free( controlPubKey );
            X509_free( ControlCert );
            BN_free( serverPriBn );
            EC_POINT_free( controlPubEc );
            OPENSSL_free( hmac_value );
            close( accept_fd );
            return;
        }
        size_t sendDataLen = hmacMessageString.size();

        memcpy( sendBuff, hmacMessageString.c_str(), sendDataLen );
        //发送
        n = write( accept_fd, sendBuff, sendDataLen );
        // std::cout << n << std::endl;
        //  std::cout << symmetricKey << std::endl;
        setSocketNodelay( accept_fd );
        std::shared_ptr< DdapData > req_info( new DdapData( loop, accept_fd, symmetricKey ) );
        req_info->getChannel()->setHolder( req_info );
        // std::cout << "611" << std::endl;
        req_info->bindDispatcher( dispatcher_ );
        loop->queueInLoop( std::bind( &DdapData::newEvent, req_info ) );
        loop->doPendingFunctors();
        std::cout << "accpet_fd: " << accept_fd << "双向认证通过，安全连接成功！" << std::endl;
        X509_free( ControlCert );
        // EVP_PKEY_free( serPri );
        // BN_free( serverPriBn );
        OPENSSL_free( hmac_value );
        EVP_PKEY_free( controlPubKey );
        EC_POINT_free( controlPubEc );
    }

}  // namespace droneswarm